package com.ccys.doctor.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.ccys.common.constants.ContextConstants;
import com.ccys.common.enums.CodeEnum;
import com.ccys.common.third.mailGun.MailgunUtil;
import com.ccys.common.util.*;
import com.ccys.common.vo.ResponseResultApp;
import com.ccys.db.cache.UserUtil;
import com.ccys.db.dto.doctor.login.DoctorLoginDto;
import com.ccys.db.dto.login.ForgotPasswordDto;
import com.ccys.db.entity.TblDoctor;
import com.ccys.db.entity.TblMember;
import com.ccys.db.mapper.TblBookingMapper;
import com.ccys.db.mapper.TblDoctorClinicMapper;
import com.ccys.db.mapper.TblDoctorMapper;
import com.ccys.db.vo.doctor.login.ClinicListByDoctorVo;
import com.ccys.doctor.service.DoctorPcLoginService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.*;

/**
 * @program: WhiteCoat
 * @description: 医生登录相关接口
 * @author: ZhangJingCan
 * @create: 2024-02-05 09:34
 **/

@Service
public class DoctorPcLoginServiceImpl implements DoctorPcLoginService {

    @Resource
    private TblBookingMapper tblBookingMapper;

    @Resource
    private TblDoctorMapper tblDoctorMapper;

    @Resource
    private TblDoctorClinicMapper tblDoctorClinicMapper;

    @Override
    public ResponseResultApp getCountOfWaitingApproval(String patientCountryOfResidence, String doctorCountryOfResidence) {
        if (ObjectUtil.isEmpty(patientCountryOfResidence) || ObjectUtil.isEmpty(doctorCountryOfResidence)) {
            return ResponseResultApp.error("Parameter abnormality");
        }
        TblDoctor doctor = UserUtil.getCurLoginDoctor();
        //必须满足才进入查询sql - 否则直接return-1
        if (ObjectUtil.isNotEmpty(doctor.getAllowApproveMedication()) && doctor.getAllowApproveMedication() == 1
                && doctor.getCountryOfResidence().equals(patientCountryOfResidence)) {
            return ResponseResultApp.success(tblBookingMapper.getCountOfWaitingApproval(patientCountryOfResidence, doctorCountryOfResidence));
        }
        return ResponseResultApp.success(-1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResultApp updateClinic(String clinicId) {
        if (ObjectUtil.isEmpty(clinicId)) {
            return ResponseResultApp.error("The request is invalid.");
        }
        TblDoctor doctor = UserUtil.getCurLoginDoctor();
        doctor.setCurrentClinicId(clinicId);
        tblDoctorMapper.updateByPrimaryKeySelective(doctor);
        return ResponseResultApp.success();
    }

    @Override
    public ResponseResultApp<List<ClinicListByDoctorVo>> getClinicByDoctor() {
        //获取登录的医生
        TblDoctor doctor = UserUtil.getCurLoginDoctor();
        List<ClinicListByDoctorVo> list = tblDoctorClinicMapper.getClinicByDoctor(doctor.getId());
        return ResponseResultApp.success(list);
    }

    @Override
    public Object login(DoctorLoginDto dto) {
        Map<String, Object> map = new HashMap<>();
        //传入的参数校验
        if (ObjectUtil.isEmpty(dto.getEmail()) || ObjectUtil.isEmpty(dto.getPassword())) {
            map.put("error", 400);
            map.put("error_description", "Please try again or click on the Sign Up link below to create a new account with us.");
            return map;
        }

        if (ObjectUtil.isEmpty(dto.getGrant_type()) || !"password".equals(dto.getGrant_type())) {
            map.put("error", "unsupported_grant_type");
            return map;
        }
        if (ObjectUtil.isEmpty(dto.getAccount_type()) || !"doctor".equals(dto.getAccount_type())) {
            map.put("error", 401);
            map.put("error_description", "Request require authorization.");
            return map;
        }

        //按条件查询医生
        Example doctorExample = new Example(TblDoctor.class);
        doctorExample.createCriteria()
                .andEqualTo("email", dto.getEmail())
                .andEqualTo("status", 1)
                .andEqualTo("delFlag", 0);
        TblDoctor doctor = tblDoctorMapper.selectOneByExample(doctorExample);
        //不存在则返回错误信息
        if (ObjectUtil.isEmpty(doctor)) {
            map.put("error", 406);
            map.put("error_description", "Account could not be found.");
            return map;
        }
        String hash = PBKDF2Util.createHashPassword(dto.getPassword(), doctor.getIterationPassword(), doctor.getSaltPassword());
        // 校验登录密码
        boolean b = PBKDF2Util.verifyPassword(dto.getPassword(), doctor.getIterationPassword(), hash);
        if (!b) {
            //密码错误
            map.put("error", 400);
            map.put("error_description", "Please try again or click on the Sign Up link below to create a new account with us.");
            return map;
        }

        //检查账户是否被锁定
        if (doctor.getFailedPasswordAttempts() >= 3) {
            //达到三次就肯定有锁定时间
            if (doctor.getLockedOn().getTime() > new Date().getTime()) {
                //如果锁定时间大于当前时间 - 返回错误信息
                map.put("error", 407);
                map.put("error_description", "Your account has been locked.");
                return map;
            } else {
                //锁定时间过了 - 设置一下错误次数？
                doctor.setFailedPasswordAttempts(0);
                //账号登录状态，密码错误 3 次修改为0，默认 1
                //也设置为1
                doctor.setLoginStatus(1);
            }
        }

        //设置为在线状态
        doctor.setOnlineStatus(1);
        //修改医生数据进数据库
        tblDoctorMapper.updateByPrimaryKeySelective(doctor);
        //todo token处理或许有问题，这里是返回的uuid并且存入redis的key为doctor的ID
        String token = Kit.get32UUID();
        //存入redis并设置过期时间
        JedisUtil.setexObj(doctor.getId(), ContextConstants.DEFAULT_PATIENT_EXPIRES_TIME.intValue(), token, CodeEnum.REDIS_USER.codeOf());
        //生成token
        map.put("access_token", token);
        map.put("token_type", "bearer");
        map.put("expires_in", ContextConstants.DEFAULT_PATIENT_EXPIRES_TIME);
        map.put(".issued", Kit.formatGmtDate(new Date()));
        map.put(".expires", Kit.formatAddSecondGmtDate(new Date(), ContextConstants.DEFAULT_NOT_OPERATED_TIME));
        return map;
    }

    @Override
    public ResponseResultApp forgotPassword(ForgotPasswordDto dto) {
        //校验国际邮箱是否邮箱格式
        if(StringUtils.isEmpty(dto.getEmail()) || !Kit.validateInternationalEmail(dto.getEmail())) {
            return ResponseResultApp.error(400,"The email address is invalid. Please re-enter your email address.");
        }
        String html = "";
        Example example = new Example(TblDoctor.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("email",dto.getEmail());
        criteria.andEqualTo("delFlag",0);
        List<TblDoctor> list = tblDoctorMapper.selectByExample(example);
        if(list.isEmpty()){
            return ResponseResultApp.error("Your login ID is invalid. Please re-enter your email address / identification number.");
        }
        TblDoctor oneByLimit = list.get(0);

        // 读取邮件模板
        try {
            String fullName = oneByLimit.getFirstName();
            if(StringUtil.isNotEmpty(oneByLimit.getLastName())) {
                fullName = fullName + " " + oneByLimit.getLastName();
            }
            String templateContent = HtmlUtils.getTemplateContent("Account_Recovery.ftl", null);
            //替换内容
            templateContent = templateContent.replace("[Patient_Name]", fullName);

            //判断是否有没有使用的修改密码令牌
            String token = JedisUtil.get("forgotPassword:"+oneByLimit.getId(), CodeEnum.REDIS_UPDATE_PROFILE.codeOf());
            if(StringUtils.isNotBlank(token)){
                JedisUtil.del(token,CodeEnum.REDIS_UPDATE_PROFILE.codeOf());
            }
            token = IdUtil.fastUUID();
            JSONObject json = new JSONObject();
            json.put("type","doctor");
            json.put("id",oneByLimit.getId());
            JedisUtil.set("forgotPassword:"+oneByLimit.getId(),token,CodeEnum.REDIS_UPDATE_PROFILE.codeOf());
            JedisUtil.set(token,json.toJSONString(),CodeEnum.REDIS_UPDATE_PROFILE.codeOf());

            //TODO 替换重置密码路径  前端需要提供网页地址
            String url = "www.whitecoat.global";
            templateContent = templateContent.replace("[Reset_Password_Url]", url+"?token="+token);

            html = templateContent;
        } catch (Exception e) {
            e.printStackTrace();
        }
        boolean b = MailgunUtil.sendEmail(dto.getEmail(), "Forgot Your Password?","Did you request this password reset? If you suspect any suspicious activity, please get in touch with us at contactus@whitecoat.global",html);
        if(b) {
            return ResponseResultApp.success("We have received your request. Please check your email and follow the instructions to reset your password.",null);
        }else{
            return ResponseResultApp.error(400,"Please try again after 5 minutes !");
        }

    }
}
